package main

import (
	"github.com/spf13/pflag"
	"io"
	"bufio"
	"os/exec"
	"fmt"
	"os"
)

//args struct
type selpg_args struct {
	start_page int
	end_page int
	in_filename string
	page_len int
	page_type bool
	print_dest string
}

var progname string   //程序名

const INT_MAX = int(^uint(0) >> 1);  //所有位数取0，取反，最后右移一位

//处理参数
func (sa *selpg_args) process_args() {

	pflag.IntVarP(&sa.start_page, "start_page", "s", 0, "Start page")
	pflag.IntVarP(&sa.end_page, "end_page", "e", 0, "End page")
	pflag.BoolVarP(&sa.page_type, "page_type", "f", false, "Page type")
	pflag.IntVarP(&sa.page_len, "page_len", "l", 72, "Lines per page")
	pflag.StringVarP(&sa.print_dest, "dest", "d", "", "Destination")
	pflag.Usage = func() {
		usage()
		pflag.PrintDefaults()
	}
	pflag.Parse()
	sa.in_filename = ""
	if remain := pflag.Args(); len(remain) > 0 {
		sa.in_filename = remain[0]
	}

	//参数是否合法
	//参数不够
	if len(os.Args) < 3 { 
		fmt.Fprintf(os.Stderr, "%s:  not enough arguments\n", progname)
		pflag.Usage()
		os.Exit(1)
	}
	//起始页非法
	if sa.start_page < 1 || sa.start_page > (INT_MAX-1) { 
		fmt.Fprintf(os.Stderr, "%s:  invalid start page %d\n", progname, sa.start_page)
		pflag.Usage()
		os.Exit(2)
	}
	//结束页非法
	if sa.end_page < 1 || sa.end_page > (INT_MAX-1) || sa.end_page < sa.start_page {
		fmt.Fprintf(os.Stderr, "%s:  invalid end page %d\n", progname, sa.start_page)
		pflag.Usage()
		os.Exit(3)
	}
	//页长度非法
	if sa.page_len < 1 || sa.page_len > (INT_MAX-1) {
		fmt.Fprintf(os.Stderr, "%s:  invalid page length %d\n", progname, sa.page_len)
		pflag.Usage()
		os.Exit(4)
	}
	if sa.in_filename != "" {
		if _, err := os.Stat(sa.in_filename); os.IsNotExist(err) {
			fmt.Fprintf(os.Stderr, "%s:  input file \"%s\" does not exist\n", progname, sa.in_filename)
			pflag.Usage()
			os.Exit(5)
		}
	}
}

//运行逻辑
func (sa selpg_args) process_input() {
	 var reader *bufio.Reader //读取输入
	 var writer io.WriteCloser //写入输出

	 //reader
	 if sa.in_filename == "" {
		 reader = bufio.NewReader(os.Stdin)
	 } else {
		 fin, err := os.Open(sa.in_filename)
		 if err != nil {
			 fmt.Fprintf(os.Stderr, "%s: could not open input file \"%s\"\n", progname, sa.in_filename)
			 os.Exit(6)
		 }
		 reader = bufio.NewReader(fin)
		 defer fin.Close()
	 }
 
	 //writer
	 if sa.print_dest == "" {
		 writer = os.Stdout
	 } else {
		 cmd := exec.Command("lp","-d"+ sa.print_dest)
		 var err error
		 if writer, err = cmd.StdinPipe(); err != nil {
			 fmt.Fprintf(os.Stderr, "%s: could not open pipe to \"%s\"\n",
				 progname, sa.print_dest)
			 fmt.Println(err)
			 os.Exit(7)
		 }
		 cmd.Stdout = os.Stdout
		 cmd.Stderr = os.Stderr
		 if err = cmd.Start(); err != nil {
			 fmt.Fprintf(os.Stderr, "%s: cmd start error\n",
				 progname)
			 fmt.Println(err)
			 os.Exit(8)
		 }
	 }
 
	 line_ctr, page_ctr, pLen := 1, 1, sa.page_len
	 ptFlag := '\n'
	 if sa.page_type {
		 ptFlag = '\f'
		 pLen = 1
	 }
 
	 //用reader读取选中页的数据，写入writer
	 for {
		 line, crc := reader.ReadString(byte(ptFlag));
		 if crc != nil && len(line) == 0 {
			 break
		 }
		 if line_ctr > pLen {
			 page_ctr++
			 line_ctr = 1
		 }
		 if page_ctr >= sa.start_page && page_ctr <= sa.end_page {
			 _, err := writer.Write([]byte(line))
			 if err != nil {
				 fmt.Println(err)
				 os.Exit(9)
			 }
		 }
		 line_ctr++
	 }
 
	 //读取是否成功或者是否完成
	 if page_ctr < sa.start_page {
		 fmt.Fprintf(os.Stderr,
			 "\n%s: start_page (%d) greater than total pages (%d),"+
				 " no output written\n", progname, sa.start_page, page_ctr)
	 } else if page_ctr < sa.end_page {
		 fmt.Fprintf(os.Stderr, "\n%s: end_page (%d) greater than total pages (%d),"+
			 " less output than expected\n", progname, sa.end_page, page_ctr)
	 }
 }
 
func usage() {
	fmt.Fprintf(os.Stderr, "\nUSAGE: %s -sstart_page -eend_page [ -f | -llines_per_page ] [ -ddest ] [ in_filename ]\n", progname)
}

func main() {
	sa := selpg_args{}
	progname = os.Args[0]
	sa.process_args()
	sa.process_input()
}